﻿using System;
using SlimDX;
using SlimDX.DirectInput;
using System.Globalization;
using System.Threading;
using System.Windows.Forms;

namespace JoyState
{
    public class JoyState
    {
        readonly EventArgs e = new EventArgs();
        public EventHandler NoJoy;
        public EventHandler Updated;
        public EventHandler Error;
        public EventHandler Created;
        public EventHandler Released;
        public EventHandler Started;
        public EventHandler Stopped;

        Joystick mJoystick;
        JoystickState mState = new JoystickState();
        
        int mNumPoVs;
        int mSliderCount;

        bool mEnd;
        public bool IsRun
        {
            get { return !mEnd; }
        }
        Thread mTimer;

        public void JoyStateInit(Form form)
        {
            // make sure that DirectInput has been initialized
            DirectInput dinput = new DirectInput();

            // search for devices
            foreach (DeviceInstance device in dinput.GetDevices(DeviceClass.GameController, DeviceEnumerationFlags.AttachedOnly))
            {
                // create the device
                try
                {
                    mJoystick = new Joystick(dinput, device.InstanceGuid);
                    mJoystick.SetCooperativeLevel(form, CooperativeLevel.Exclusive | CooperativeLevel.Foreground);
                    break;
                }
                catch (DirectInputException) { }
            }

            if (mJoystick == null)
            {
                if (Error != null)
                    Error.Invoke("There are no joysticks attached to the system.", e);
                if (NoJoy != null)
                    NoJoy.Invoke(this, e);
                return;
            }

            foreach (DeviceObjectInstance deviceObject in mJoystick.GetObjects())
            {
                if ((deviceObject.ObjectType & ObjectDeviceType.Axis) != 0)
                    mJoystick.GetObjectPropertiesById((int)deviceObject.ObjectType).SetRange(-1000, 1000);

                UpdateControl(deviceObject);
            }
            // acquire the device
            mJoystick.Acquire();

            if (Created != null) Created.Invoke(this, e);
        }

        public void StartReading()
        {
            if (Updated != null)
            {
                mEnd = false;
                mTimer = new Thread(TimerThread);
                mTimer.Start();
            }
            else throw new Exception("Please setup Updated EventHandler.");
        }
        public void StopReading() { mEnd = true; }

        bool ReadImmediateData()
        {

            if (mJoystick.Acquire().IsFailure)
                return false;

            if (mJoystick.Poll().IsFailure)
                return false;

            mState = mJoystick.GetCurrentState();
            if (Result.Last.IsFailure)
                return false;

            //UpdateUI();
            return true;

        }
        void ReleaseDevice()
        {
            if (mJoystick != null)
            {
                mJoystick.Unacquire();
                mJoystick.Dispose();
            }
            mJoystick = null;
            Created.Invoke(this, e);
        }

        void TimerThread()
        {
            if (Started != null)
                Started.Invoke(this, e);
            while (!mEnd)
            {
                //joystick.Acquire();
                if (ReadImmediateData()) Update();
                // set the timer to go off 10 times a second to read input
                // NOTE: Normally applications would read this much faster.
                Thread.Sleep(1000 / 250);
            }
            if (Stopped != null)
                Stopped.Invoke(this, e);
        }

        void Update()
        {
            if (mJoystick == null)
            {
                Released.Invoke(this, e);
                mEnd = true;
            }

            string strText = null;

            int[] states = new int[2];
            states[0] = mState.X;
            states[1] = mState.Y;
            //states[2] = state.Z.ToString(CultureInfo.CurrentCulture);

            //label_XRot.Text = state.RotationX.ToString(CultureInfo.CurrentCulture);
            //label_YRot.Text = state.RotationY.ToString(CultureInfo.CurrentCulture);
            //label_ZRot.Text = state.RotationZ.ToString(CultureInfo.CurrentCulture);

            int[] slider = mState.GetSliders();

            //label_S0.Text = slider[0].ToString(CultureInfo.CurrentCulture);
            //label_S1.Text = slider[1].ToString(CultureInfo.CurrentCulture);

            int[] pov = mState.GetPointOfViewControllers();

            //label_P0.Text = pov[0].ToString(CultureInfo.CurrentCulture);
            //label_P1.Text = pov[1].ToString(CultureInfo.CurrentCulture);
            //label_P2.Text = pov[2].ToString(CultureInfo.CurrentCulture);
            //label_P3.Text = pov[3].ToString(CultureInfo.CurrentCulture);

            bool[] buttons = mState.GetButtons();

            for (int b = 0; b < buttons.Length; b++)
            {
                if (buttons[b])
                    strText += b.ToString("00 ", CultureInfo.CurrentCulture);
            }
            //label_ButtonList.Text = strText;

            Updated.Invoke(states, e);
        }

        void UpdateControl(DeviceObjectInstance d)
        {
            //Doing some configurations

            //if (ObjectGuid.XAxis == d.ObjectTypeGuid)
            //{
            //    label_XAxis.Enabled = true;
            //    label_X.Enabled = true;
            //}
            //if (ObjectGuid.YAxis == d.ObjectTypeGuid)
            //{
            //    label_YAxis.Enabled = true;
            //    label_Y.Enabled = true;
            //}
            //if (ObjectGuid.ZAxis == d.ObjectTypeGuid)
            //{
            //    label_ZAxis.Enabled = true;
            //    label_Z.Enabled = true;
            //}
            //if (ObjectGuid.RotationalXAxis == d.ObjectTypeGuid)
            //{
            //    label_XRotation.Enabled = true;
            //    label_XRot.Enabled = true;
            //}
            //if (ObjectGuid.RotationalYAxis == d.ObjectTypeGuid)
            //{
            //    label_YRotation.Enabled = true;
            //    label_YRot.Enabled = true;
            //}
            //if (ObjectGuid.RotationalZAxis == d.ObjectTypeGuid)
            //{
            //    label_ZRotation.Enabled = true;
            //    label_ZRot.Enabled = true;
            //}

            //if (ObjectGuid.Slider == d.ObjectTypeGuid)
            //{
            //    switch (SliderCount++)
            //    {
            //        case 0:
            //            label_Slider0.Enabled = true;
            //            label_S0.Enabled = true;
            //            break;

            //        case 1:
            //            label_Slider1.Enabled = true;
            //            label_S1.Enabled = true;
            //            break;
            //    }
            //}

            //if (ObjectGuid.PovController == d.ObjectTypeGuid)
            //{
            //    switch (numPOVs++)
            //    {
            //        case 0:
            //            label_POV0.Enabled = true;
            //            label_P0.Enabled = true;
            //            break;

            //        case 1:
            //            label_POV1.Enabled = true;
            //            label_P1.Enabled = true;
            //            break;

            //        case 2:
            //            label_POV2.Enabled = true;
            //            label_P2.Enabled = true;
            //            break;

            //        case 3:
            //            label_POV3.Enabled = true;
            //            label_P3.Enabled = true;
            //            break;
            //    }
            //}
        }

    }
}

